#pragma once

#include <dbformat.h>
#include <skiplist.h>
#include <arena.h>
#include <db.h>

namespace minidb
{
class InternalKeyComparator;
class MemTableIterator;

/// TODO: 弄懂coding那堆函数到底是干嘛用的
/// TODO: 搞懂skiplist的实现，以及里面保存的到底是什么数据
/// TODO: 搞懂MemTable的结构、每条Entry的format是什么意思

class MemTable
{
public:
    explicit MemTable(const InternalKeyComparator &comparator);

    MemTable(const MemTable &) = delete;
    MemTable &operator=(const MemTable &) = delete;

    void Ref()
    {
        ++refs_;
    }

    void UnRef()
    {
        --refs_;
        assert(refs_ >= 0);
        if (refs_ <= 0)
        {
            delete this;
        }
    }

  // Returns an estimate of the number of bytes of data in use by this
  // data structure. It is safe to call when MemTable is being modified.
  size_t ApproximateMemoryUsage();

  // Return an iterator that yields the contents of the memtable.
  //
  // The caller must ensure that the underlying MemTable remains live
  // while the returned iterator is live.  The keys returned by this
  // iterator are internal keys encoded by AppendInternalKey in the
  // db/format.{h,cc} module.
  Iterator* NewIterator();

  // Add an entry into memtable that maps key to value at the
  // specified sequence number and with the specified type.
  // Typically value will be empty if type==kTypeDeletion.
  void Add(SequenceNumber seq, ValueType type, const Slice& key,
           const Slice& value);

  // If memtable contains a value for key, store it in *value and return true.
  // If memtable contains a deletion for key, store a NotFound() error
  // in *status and return true.
  // Else, return false.
  bool Get(const LookupKey& key, std::string* value, Status* s);

 private:
  friend class MemTableIterator;
  friend class MemTableBackwardIterator;

    struct KeyComparator
    {
        const InternalKeyComparator comparator;
        explicit KeyComparator(const InternalKeyComparator &c) :
            comparator(c)
        {
        }

        int operator()(const char *a, const char *b) const;
    };

    ~MemTable() // private, only UnRef should be used to delete it
    {
        assert(refs_ == 0);
    }

private:
    using Table = SkipList<const char*, KeyComparator>;

    int refs_;
    KeyComparator comparator_;
    Arena arena_;
    Table table_;
};
} // namespace minidb